pub trait Vertex : bytemuck::Pod {
    fn layout() -> &'static wgpu::VertexBufferLayout<'static>;
}

pub struct MeshData<V: Vertex> {
    pub vertices: Vec<V>,
    pub indices: Vec<u32>
}

#[repr(C)]
#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
pub struct TexVertex {
    pub position: [f32; 3],
    pub tex_coords: [f32; 2]
}

impl Vertex for TexVertex {
    fn layout() -> &'static wgpu::VertexBufferLayout<'static> {
        const LAYOUT: wgpu::VertexBufferLayout = wgpu::VertexBufferLayout {
            array_stride: std::mem::size_of::<TexVertex>() as wgpu::BufferAddress,
            step_mode: wgpu::VertexStepMode::Vertex,
            attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x2]
        };

        &LAYOUT
    }
}

pub struct Mesh {
    pub layout: &'static wgpu::VertexBufferLayout<'static>,
    pub vertex_buffer: wgpu::Buffer,
    pub index_buffer: wgpu::Buffer,
    pub draw_cnt: u32
}

impl Mesh {
    pub fn from_data<V: Vertex>(device: &wgpu::Device, mesh_data: &MeshData<V>) -> Self {
        use wgpu::util::DeviceExt;

        let layout = V::layout();

        let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
            label: Some("Vertex Buffer"),
            contents: bytemuck::cast_slice(&mesh_data.vertices),
            usage: wgpu::BufferUsages::VERTEX
        });

        let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
            label: Some("Index Buffer"),
            contents: bytemuck::cast_slice(&mesh_data.indices),
            usage: wgpu::BufferUsages::INDEX
        });

        let draw_cnt = mesh_data.indices.len() as u32;

        Self {
            layout,
            vertex_buffer,
            index_buffer,
            draw_cnt
        }
    }
}
